#pragma once
#include "api.hpp"

namespace opengl {

struct image2d {
    i32 width = 0;
    i32 height = 0;
    u32 format = 0;
    const voidptr data = nullptr;
};

class texture2d {
public:
    /* enums */
    enum wrapping : u32 {
        repeat = 0x2901,          // GL_REPEAT
        mirrored_repeat = 0x8370, // GL_MIRRORED_REPEAT
        clamp_to_edge = 0x812F,   // GL_CLAMP_TO_EDGE
        clamp_to_border = 0x812D  // GL_CLAMP_TO_BORDER
    };

    enum filter : u32 {
        nearest = 0x2600,                // GL_NEAREST
        linear = 0x2601,                 // GL_LINEAR
        nearest_mipmap_nearest = 0x2700, // GL_NEAREST_MIPMAP_NEAREST
        linear_mipmap_nearest = 0x2701,  // GL_LINEAR_MIPMAP_NEAREST
        nearest_mipmap_linear = 0x2702,  // GL_NEAREST_MIPMAP_LINEAR
        linear_mipmap_linear = 0x2703    // GL_LINEAR_MIPMAP_LINEAR
    };

public:
    static bool auto_generate_mipmaps;

public:
    /* Constructors */
    OPENGLAPI texture2d();
    OPENGLAPI texture2d(const image2d &image, u32 wrappingX = repeat, u32 wrappingY = repeat, u32 min_filter = nearest,
                        u32 mag_filter = nearest,
                        i32 mipmap_levels = 4);      // Create a texture from an image
    OPENGLAPI texture2d(const texture2d &) = delete; // Use copy_from instead
    OPENGLAPI texture2d(texture2d &&other);          // Move constructor
    void create(const image2d &image = {}, u32 wrappingX = repeat, u32 wrappingY = repeat, u32 min_filter = nearest,
                u32 mag_filter = nearest, i32 mipmap_levels = 4);
    /* Member functions */
    OPENGLAPI void generate_mipmap() const;
    OPENGLAPI void set_data(const void *data, u32 width, u32 height, u32 format,
                            i32 level = 0) const; // Texture data is immutable after creation
    OPENGLAPI void set_wrapping(u32 wrappingX, u32 wrappingY) const;
    OPENGLAPI void set_filter(u32 min_filter, u32 mag_filter) const;

    /* Texture binding */
    OPENGLAPI void bind_to(u32 unit) const;

    /* Operator overloads */
    OPENGLAPI texture2d &operator=(const texture2d &) = delete;
    OPENGLAPI texture2d &operator=(texture2d &&other);

    /* Destructor */
    OPENGLAPI ~texture2d(); // Delete the texture if it was created

public:
    u32 id;
};

} // namespace opengl